        TITL DAI FIRMWARE DD1A-DEB4  V1.0  Rev.1
        ORG   :DD1A
*
*
*
*******************
* INPUT TEXT LINE *
*******************
*
* Part of 'restart interpreter' (C853).
* Scans keyboard and reads in a line on the current
* screen line, up until car.ret. First prints
* car.ret and a prompt ('*').
* The routine can be aborted on car.ret or Break
* only.
*
* Entry: A: Contains prompt.
* Exit:  CY=1: Break pressed.
*        CY=0: HL:  Address 1st character on line.
*              C=1: Offset 1st significant character.
*              ABDEHL preserved.
*
INPL0   PUSH  PSW
        CALL  :DD55     Cursor to column 0
        POP   PSW       Get prompt
INPLN   STC             CY=1
        PUSH  PSW
        PUSH  H         Save cursor coord 1st char
IPL10   CALL  :DD6A     Print prompt
        LXI   H,:02B9
        MVI   M,:00     Enable complete keyb.scan
IPL20   CALL  :D6BE     Get keyb. input
        JC    :DD49     Ignore line if Break pressed
        JZ    :DD2A     Wait for input
        CPI   :20       Printable character?
        JNC   :DD22     Print it and get next one
        CPI   :08       Backspace
        JZ    :DD22     Print it; get next char
        CPI   :0D       Car.ret?
        JNZ   :DD2A     Get next char if not
 REM
* Exit on car.ret:
 REM
        DCR   M         Set KBRFL for BREAK only
        MVI   C,:01
EXIT1   POP   H         Get cursor coord 1st char
        POP   PSW       Get prompt
        CMC             CY=0
        RET
 REM
* Exit on Break:
 REM
IPL30   DCR   M         Set KBRFL for BREAK only
        MVI   A,:21
        CALL  :DD60     Print '!'
        CALL  :DD5E     Print car.ret
        POP   H
        POP   PSW       Get prompt, CY=1
        RET
*
**********************
* CURSOR TO COLUMN 0 *
**********************
*
* The X-coordinate of the cursor is checked.
* If not 0, a car.ret is printed.
*
* Entry: None.
* Exit:  AF corrupted. BCDEHL preserved.
*
COL0    PUSH  D
        PUSH  H
        RST   5         Get cursor pos (HL) and size
        DATA  :0C       char.screen (DE)
        MOV   A,L       X-coord cursor in A
        POP   H
        POP   D
        ORA   A
        RZ              Abort if cursor in Col.0
CRLF    MVI   A,:0D     Else: print CR
*
* GENERAL OUTPUT ROUTINE:
*
* Outputs a character in a direction depending
* on OTSW (#0131).
*
* Entry: A: Character to be transmitted.
* Exit:  AF corrupted.
*
*SCCHR
OUTC    PUSH  PSW       Preserve char
        LDA   :0131
        CPI   :02       Check output direction
        JNC   :DD70     If to edit buf/DOUTC
 REM
* To screen/RS232 - OTSW=0/1:
 REM
        POP   PSW       Get char
COUTC   RST   5         Character to screen
        DATA  :03
        CNC   :D642     Output to RS232 if reqd
        RET
 REM
* To DOUTC - OTSW=3:
 REM
OTC10   NOP
        JNZ   :D74C     Character to DOUTC
 REM
* To editbuffer - OTSW=2:
 REM
        POP   PSW       Get char
OTBIN   PUSH  PSW
        PUSH  H
        PUSH  D
        LHLD  :00A4     Get edit input pointer
        MOV   M,A       Byte in edit buffer
        INX   H
        SHLD  :00A4     Update edit input pointer
        XCHG            in DE
        LHLD  :00A6     Get end edit buffer
        CALL  :DE14     Calculate free buffer space
        JC    :DD8E     If edit buffer full
        POP   D
        POP   H
OTC99   POP   PSW
        RET
 REM
* If edit buffer full:
 REM
OTC20   CALL  :DECA     Heap back to right size
        JMP   :DA10     Run error 'OUT OF MEMORY'
*
*******************
* OUTPUT TO RS232 *
*******************
*
* Transmits a character to the RS232 interface via
* the TICC if the interface is ready for it.
* In case of a car.ret, also a line feed is send.
*
* Entry: A: Character to be transmitted.
* Exit:  ABCDEHL preserved, F corrupted.
*
OUTSE   PUSH  PSW       Preserve char
OTS10   LDA   :FD00
        ANI   :08       Check peripheral ready
        JZ    :DD95     Wait untill ready
OTS20   LDA   :FFF3
        ANI   :10       Check TICC buffer empty
        JZ    :DD9D     Wait untill empty
        POP   PSW       Get char
        STA   :FFF6     Load serial output buffer
        CPI   :0D       Carriage return?
        RNZ             Ready if not
 REM
* If car.ret:
 REM
        PUSH  PSW
        MVI   A,:0A
        CALL  :DD94     Send line feed too
        POP   PSW
        RET
*
********************
* INPUT FROM RS232 *
********************
*
* Gets inputs from RS232 via TICC. Only 7-bit
* Ascii-code is accepted.
*
* Entry: No conditions.
* Exit:  A: Character received (0 if nothing).
*        BCDEHL preserved.
*
*CINC
INSER   LDA   :FFF3
        ANI   :08       Check if something received
        RZ              Abort if no reception
        LDA   :FFF0     Received char in A
        ANI   :7F       Mask bit 7
        RET
*
**********************************
* RS232 FRAME ERROR - (not used) *
**********************************
*
* Break test for serial input line.
*
BRSER   LDA   :FFF3
        RAR
        RNC             Abort if no break
BRS10   LDA   :FFF3     If break: check again
        RAR
        JC    :DDC5     Wait until end of break
        LDA   :FFF0     Load received character
        CMC             Set CY=1
        RET
*
*
*  ===========================
*** ENCODING SERVICE ROUTINES ***
*  ===========================
*
*
* The following routines are used both in 'main'
* and 'decode' modules.
*
************************************************
* GET CHARACTER FROM LINE, NEGLECT TAB + SPACE *
************************************************
*
* Entry: C: Position on current line.
* Exit:  Character in A; tab and space neglected.
*        C: Points to next character.
*        BDEHL preserved.
*
IGNBR   INR   C         Pnts to next char
IGNB    CALL  :DDE0     Get char from line
        CPI   :20       Space?
        JZ    :DDD1     Then get next char
        CPI   :09       Tab?
        JZ    :DDD1     Then get next char
        RET
*
***************************
* GET CHARACTER TO ENCODE *
***************************
*
* Returns a character from some position on the
* current line. The source is determined by EFSW.
*
* Entry: C: Position on current line (max. 219).
* Exit:  EFSW=0  - Keyboard: Char on line pos in A.
*        EFSW>=2 - Edit buf: Char on EFEPT + line
*                            pos in A.
*        EFSW=1  - String:   Idem. If COUNT=line pos
*                            then char is car.ret.
*        F corrupted, BCDEHL preserved.
*
EFETCH  LDA   :0135
        CPI   :01       Check input direction
        JC    :DDFF     If from keyb/RS232
        JNZ   :DDF4     If from edit buffer
 REM
* If from string:
 REM
        LDA   :0134     If string: Get COUNT
        CMP   C         COUNT=pos.on curr.line?
        MVI   A,:0D     Then char is car.ret
        JZ    :DDFE     And abort
 REM
* Entry if from edit buffer:
 REM
EFC10   PUSH  H
        LHLD  :0132     Get EFEPT
        MOV   A,C
        CALL  :DE30     Add curr.line pos to EFEPT
        MOV   A,M       Get character
        POP   H
EFC20   RET
 REM
* If from screen:
 REM
EFC30   RST   5         Get character from line
        DATA  :15
        RET
*
*
*  ==================================
*** SINGLE AND DOUBLE BYTE UTILITIES ***
*  ==================================
*
*
*********************************
* CHECK IF UPPER CASE CHARACTER *
*********************************
*
* Entry: A: Character to be checked.
* Exit:  CY=0: Not upper case.
*        CY=1: Upper case.
*        ABCDEHL preserved, F corrupted.
*
ALPHA   CPI   :41       Lowest upper case char
        CMC
        RNC
        CPI   :5B       First lower case char
        RET
*
**********************************************
* CHECK IF CHARACTER IS NUMBER OR UPPER CASE *
**********************************************
*
* Entry: A: Character to be checked.
* Exit:  CY=0: Not number, not upper case.
*        CY=1: Number or upper case.
*        ABCDEHL preserved. F corrupted.
*
ALNUM   CALL  :DE02     Check if upper case
        RC
NUMER   CPI   :30       Lowest number
        CMC
        RNC
        CPI   :3A       No number anymore
        RET
*
*********************
* COMPARE HL AND DE *
*********************
*
* Compares HL with DE (HL-DE).
*
* Exit: DE=HL: Z=1, CY=0.
*       DE<HL: Z=0, CY=0.
*       DE>HL: Z=0, CY=1.
*       BCDEHL preserved, AF corrupted.
*
COMP    MOV   A,H
        CMP   D
        RNZ
        MOV   A,L
        CMP   E
        RET
*
*****************************
* CALCULATE LENGTH OF BLOCK *
*****************************
*
* Sets HL=HL-DE.
*
* Entry: Startaddress in DE, 1st address after
*        block in HL.
* Exit:  Length in HL, startaddress in DE.
*        If DE>HL, length in 2-complement.
*        ABCDE preserved, F as in COMP.
*
SUBDE   PUSH  B
        PUSH  PSW
        MOV   A,L
        SUB   E         Calc. difference lowest byte
        MOV   L,A
        MOV   A,H
        SBB   D         Calc. diff. highest byte
        MOV   H,A
        POP   B
        MOV   A,B
        POP   B
        RET
*
******************************
* DOUBLE BYTE TWO COMPLEMENT *
******************************
*
* Sets HL=-HL.
*
* Entry: Double byte to be converted in HL.
* Exit:  Two complement in HL. ABCDEF preserved.
*
CMPHL   PUSH  PSW
        MOV   A,H
        CMA             Complement H
        MOV   H,A
        MOV   A,L
        CMA             Complement L
        MOV   L,A
        INX   H         Add 1
        POP   PSW
        RET
*
**************************
* ADD OFF-SET TO ADDRESS *
**************************
*
* Adds a given offset to a base address (HL=HL+A).
*
* Entry: Base in HL, offset in A.
* Exit:  HL=HL+A. ABCDE preserved, F corrupted.
*
DADA    PUSH  PSW
        ADD   L
        MOV   L,A       L=L+A
        MOV   A,H
        ACI   :00       Add carry if overflow
        MOV   H,A
        POP   PSW
        RET
*
**********************************
* CALCULATE ADDRESS AFTER STRING *
**********************************
*
* Sets HL=HL+M+1.
*
* Entry: HL points to 1st byte of string (length
*        byte).
* Exit:  HL points to first byte after string.
*        AFBCDE preserved.
*
DADM    PUSH  PSW
        MOV   A,M       Get length of string
        INX   H         HL: addr. 1st char. byte
        CALL  :DE30     Calc addr after string
        POP   PSW
        RET
*
*****************
* DELAY ROUTINE *
*****************
*
* Runs a fixed delay loop of 665 msec. If
* interrupts are enabled, the delay will be
* approx. 750 msec.
* HL is loaded with FFFF, and then decremented.
*
* Exit: ABCDEHL preserved; F corrupted.
*
DELAY   PUSH  H
        PUSH  D
        LXI   H,:FFFF   Init. delay value
        MOV   D,H
        MOV   E,L
DLY10   DAD   D
        JC    :DE48     Repeat if not ready
        POP   D
        POP   H
        RET
*
***********************
* DATA BLOCK TRANSFER *
***********************
*
* Moves a block of data starting at (DE) and
* ending at (HL)-1 to (BC).
*
* Entry: DE: Startaddr. source bank.
*        BC: Startaddr. destination bank.
*        HL: Points after end source bank.
* Exit:  AF preserved, BCDEHL corrupted.
*
MOVE    PUSH  PSW
        PUSH  H
        CALL  :DE1A     Calc. length source bank
        MOV   A,C
        SUB   E
        MOV   A,B
        SBB   D
        JC    :DE6C     If destination addr. is
 REM lower than source addr.
 REM
* Destination address > source address:
 REM
        MOV   D,H
        MOV   E,L       Save length in DE
        DAD   B         Highest dest.addr. in HL
        POP   B
MOV10   MOV   A,D       Check if ready
        ORA   E
        JZ    :DE7A     Then abort
        DCX   D
        DCX   H
        DCX   B
        LDAX  B         Get byte to be transferred
        MOV   M,A       Transfer it
        JMP   :DE5F     Next one
 REM
* Destination address < source address:
 REM
MOV20   MOV   A,H
        ORA   L
        JZ    :DE79     Abort if ready
        DCX   H
        LDAX  D         Get byte to be transferred
        STAX  B         Transfer it
        INX   D
        INX   B
        JMP   :DE6C     Next byte
 REM
* If ready:
 REM
MOV30   POP   H
MOV40   POP   PSW
        RET
*
*********************************
* FILL BANK WITH IDENTICAL DATA *
*********************************
*
* Fills an area of memory with a constant.
*
* Entry: DE: Startaddr. of bank.
*        HL: Points after bank.
*        A:  Data to be loaded into bank.
* Exit:  DE: Points after bank.
*        BCHL preserved, AF corrupted.
*
FILL    PUSH  B
        MOV   B,A       Save data in B
FIL10   CALL  :DE14     Check if bank full
        JZ    :DE8D     Abort if ready
        JC    :DE8D     Abort if DE>HL
        MOV   A,B       Get data
        STAX  D         and store it
        INX   D
        JMP   :DE7E     Next addr.
FIL20   POP   B
        RET
*
********************
* MULTIPLY HL BY A *
********************
*
* Multiplies a 16-bit value by a 8-bit value.
*
* Entry: HL: 16-bit value.
*        A:  8-bit value.
* Exit:  CY=0: Result in HL.
*        CY=1: Overflow.
*        ABCDE preserved.
*
HLMUL   STC
        PUSH  PSW
        PUSH  D
        XCHG
        LXI   H,:0000   Init. result
HLM10   ORA   A
        RAR             Next bit of multiplier
        JNC   :DE9F     Jump if bit is 0
        DAD   D         Add 1* HL if bit is 1
        JC    :DEAD     Abort if overflow
HLM20   ORA   A
        JZ    :DEB1     Abort if ready
        XCHG
        DAD   H         Multiply *2
        XCHG
        JNC   :DE96     Again if no overflow
        NOP
        NOP
        NOP
        NOP
HLM90   NOP
        POP   D
        POP   PSW       Error exit if overflow
        RET
HLM99   POP   D
        POP   PSW
        CMC             No error exit
        RET
*
*
*
        UNL
CINC    EQU INSER
SCCHR   EQU OUTC
        LST
        END
